Core.Scheduler = function() {
	this.timer;
	
	this.reg = [];
	this.cache = {};
	this.interval = 10;
};

Core.Scheduler.prototype = {
	
	__clear: function() {
		this.stop();
		this.reg = [];
		this.cache = {};
	},
	
	/**
	 * Starts the scheduler.
	 */
	start: function() {
		Core.assert(Core.App.isRunning(), "Core.App needs to be running before Core.Scheduler starts.");
		this.timer = Env.later(this.interval, this, this._runLoop, [], true);
	},
	
	/**
	 * Stops the scheduler.
	 */
	stop: function() {
		if(this.timer) {
			this.timer.cancel();
			this.timer = undefined;
		}
	},
	
	/**
	 * Executes the given function once, after the given time.
	 * @param Function fn
	 * @param Number time [ms]
	 */
	once: function(fn, time) {
		var async = new Core.Scheduler.AsyncFunction(fn, time, true);
		this.schedule(async);
		return async;
	},
	
	/**
	 * Executes the given function periodically, where the interval is the given time.
	 * @param Function fn
	 * @param Number time [ms]
	 */
	periodic: function(fn, time) {
		var async = new Core.Scheduler.AsyncFunction(fn, time, false);
		
		this.schedule(async);
		return async;
	},
	
	/**
	 * Runs the functions scheduled for the current invocation loop.
	 */
	_runLoop: function() {
		var cache = this.cache;
		Array.each(this.reg.shift(), function(async) {
			cache[Core.uid(async)] = false;
			async.execute();
		});
	},
	
	/**
	 * Schedules the async object for next invocation.
	 * @param Core.Scheduler.Async async
	 * 
	 */
	schedule: function(async) {
		var	uid = Core.uid(async),
			delay = async.getDelay() / this.interval;
			delay = delay < 1 ? 0 : Math.round(delay - 1);
			
		if(this.cache[uid]) { return false; }
		else {
			if(!this.reg[delay]) { this.reg[delay] = []; }
			this.reg[delay].push(async);
			
			this.cache[uid] = true;
			return true;
		}
	}
};
Core.Scheduler = Singleton.register("core.scheduler", Core.Scheduler);

/**
 * Registers start & stop Core.Scheduler handlers.
 */
Core.App.addStartListener(Core.Scheduler.start.bind(Core.Scheduler));
Core.App.addStopListener(Core.Scheduler.stop.bind(Core.Scheduler));